#include "gzip.h"
#include "lzw.h"
#include "tailor.h"

void read_error(){}
void error(char *m){}

#define MIN(a,b) (((a) < (b))? (a) : (b))


DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
DECLARE(ush, d_buf,  DIST_BUFSIZE);
DECLARE(uch, window, 2L*WSIZE);

#ifndef MAXSEG_64K
DECLARE(ush, tab_prefix, 1L<<BITS);
#else
DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
#endif

long bytes_in;
long bytes_out;

unsigned insize;           /* valid bytes in inbuf */
unsigned inptr;            /* index of next byte to be processed in inbuf */
unsigned outcnt;           /* bytes in output buffer */

int level;
int test;
int rsync = 0;
int method;

typedef struct{
	uch *buf;
	unsigned int  cnt;
	unsigned int  size;
}mem_file;

mem_file in_mem_file = {0},out_mem_file = {0};


void warning(char const *m)
{
}

void gzip_error(char const *m)
{
}

/* ===========================================================================
* Fill the input buffer. This is called only when the buffer is empty.
*/
int fill_inbuf(int eof_ok)
{
	int len;

	/* Read as much as possible */
	insize = 0;
	do {
		len = read_buf((char*)inbuf+insize, INBUFSIZ-insize);
		if (len == 0 || len == EOF) break;
		insize += len;
	} while (insize < INBUFSIZ);

	if (insize == 0) {
		if (eof_ok) return EOF;
		read_error();
	}
	bytes_in += (ulg)insize;
	inptr = 1;
	return inbuf[0];
}

/* ===========================================================================
* Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
* (used for the compressed data only)
*/
void flush_outbuf()
{
	if (outcnt == 0) return;

	write_buf(0,(char *)outbuf, outcnt);
	bytes_out += (ulg)outcnt;
	outcnt = 0;
}

/* ===========================================================================
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
void flush_window()
{
	if (outcnt == 0) return;

	if (!test) {
		write_buf(0,(char *)window, outcnt);
	}
	bytes_out += (ulg)outcnt;
	outcnt = 0;
}

int file_read(char *buf,  unsigned size)
{
	return 0;
}

int mem_read(char *buf,  unsigned size)
{
	unsigned int len = MIN(size,in_mem_file.size - in_mem_file.cnt);

	if(len > 0)
	{
		memcpy(buf,in_mem_file.buf  + in_mem_file.cnt,len);
		in_mem_file.cnt += len;
	}

	return len;

}

int mem_write(char *buf,  unsigned size)
{
	unsigned int len = MIN(size,out_mem_file.size - out_mem_file.cnt);
	if(len > 0)
	{
		memcpy(out_mem_file.buf + out_mem_file.cnt,buf,len);
		out_mem_file.cnt += len;
	}

	return len;
}

void write_buf(int fd, voidp buf, unsigned cnt)
{
	mem_write(buf,cnt);
}

int zip_mem(char *in,int in_size,char *out,int out_size)
{
	uch  flags = 0;         /* general purpose bit flags */
	ush  attr = 0;          /* ascii/binary flag */
	ush  deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
	int  level = 6;

	bytes_in  = 0;
	bytes_out = 0;

	in_mem_file.buf = in;
	in_mem_file.cnt = 0;
	in_mem_file.size = in_size;

	out_mem_file.buf = out;
	out_mem_file.cnt = 0;
	out_mem_file.size = out_size;

	read_buf  = mem_read;
	//write_buf =	mem_write;

	outcnt = 0;

	bi_init(NO_FILE);
	ct_init(&attr, &method);
	lm_init(level, &deflate_flags);

	(void)deflate();
	flush_outbuf();

	return bytes_out;
}

int unzip_mem(char *in,int in_size,char *out,int out_size)
{
	bytes_in  = 0;
	bytes_out = 0;

	in_mem_file.buf = in;
	in_mem_file.cnt = 0;
	in_mem_file.size = in_size;

	out_mem_file.buf = out;
	out_mem_file.cnt = 0;
	out_mem_file.size = out_size;

	read_buf  = mem_read;
	//write_buf =	mem_write;

	outcnt = 0;

	method = DEFLATED;
	fill_inbuf(0);

	inptr = 0;
	inflate();
	flush_outbuf();

	return bytes_out;

}